﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace NFramework.ObjectModel
{
    public struct DirtyTrackable<T>
    {
        private T _value;
        private bool _isDirty;

        public DirtyTrackable(T value)
        {
            _value = value;
            _isDirty = false;
            _valueSet = true;
        }

        public bool HasValueSet
        { 
            get 
            {
                return _valueSet;
            }
        }
        private bool _valueSet;

        public bool IsDirty
        {
            get
            {
                return _isDirty;
            }
            set
            {
                _isDirty = value;
                _valueSet = true;
            }
        }

        public T Value
        {
            get
            {
                return _value;
            }
            set
            {
                if (!_valueSet || 
                    (value == null && _value != null) ||
                    (value != null && _value == null) ||
                    (_value != null && !_value.Equals(value)))
                {
                    _isDirty = true;
                    _value = value;
                }
                _valueSet = true;
            }
        }

        public static implicit operator T(DirtyTrackable<T> value)
        {
            return value.Value;
        }

        public static explicit operator DirtyTrackable<T>(T value)
        {
            return new DirtyTrackable<T>(value);
        }

        public override int GetHashCode()
        {
            if (_value != null) {
                return _value.GetHashCode();
            } else {
                return 0;
            }
        }

        public override bool Equals(object obj)
        {
            DirtyTrackable<T> other = (DirtyTrackable<T>)obj;
            if (other._value != null) {
                return other._value.Equals(_value);
            } else {
                return (this.Value != null);
            }
        }

        public static bool operator ==(DirtyTrackable<T> obj1, DirtyTrackable<T> obj2)
        {
            return obj1.Equals(obj2);
        }

        public static bool operator !=(DirtyTrackable<T> obj1, DirtyTrackable<T> obj2)
        {
            return !(obj1 == obj2);
        }
    }
}
